package com.quectel.util.common;

import cn.hutool.core.convert.Convert;
import com.quectel.util.ex.common.DateParseException;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * 请求帮助类
 *
 * @author: CL
 * @email: louis.cao@quectel.com
 * @date: 2019-04-01 12:29:00
 */
@Slf4j
public class Request {
    @Getter
    private Map<String, Object> params;
    @Getter
    private Integer pageNo = 1;
    @Getter
    private Integer pageSize = 10;

    private Request() {

    }

    private Request(Map<String, Object> params) {
        this.params = params;
    }


    /**
     * 解析header
     *
     * @param httpServletRequest
     * @return
     */
    public static Map<String, String> parseHeaders(HttpServletRequest httpServletRequest) {
        Map<String, String> headers = new HashMap<>();
        Enumeration<String> headerNames = httpServletRequest.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key = headerNames.nextElement();
            headers.put(key, httpServletRequest.getHeader(key));
        }
        return headers;
    }

    /**
     * 解析request object可能为数组
     *
     * @param httpServletRequest
     * @return
     */
    public static Map<String, Object> parseParams(HttpServletRequest httpServletRequest) {

        Map<String, Object> params = new HashMap<>();

        Map<String, String[]> parameterMap = httpServletRequest.getParameterMap();

        parameterMap.forEach((k, v) -> {
            if (v == null || v.length <= 0) {
                params.put(k, null);
                return;
            }
            if (v.length == 1) {
                params.put(k, StringUtils.isNotEmpty(v[0]) ? v[0] : null);
                return;
            }
            params.put(k, v);
        });
        return params;
    }

    public static Request configParams(Map<String, Object> params) {
        Request request = new Request(params);
        if (params.containsKey("pageNo")
                && params.containsKey("pageSize")
        ) {
            request.pageNo = Integer.valueOf(params.get("pageNo") + "");
            request.pageSize = Integer.valueOf(params.get("pageSize") + "");
        }


        params.put("pageNo", request.pageNo);
        params.put("pageSize", request.pageSize);

        params.put("offset", (request.pageNo - 1) * request.pageSize);
        params.put("limit", request.pageSize);
        return request;
    }

    /**
     * 不分页配置
     *
     * @param params
     * @return
     */
    public static Request configParamsNotPage(Map<String, Object> params) {
        Request request = new Request(params);
        return request;
    }

    /**
     * 手动配置页码
     *
     * @param pageNo
     * @param pageSize
     */
    public Request configPage(int pageNo, int pageSize) {
        params.put("offset", (pageNo - 1) * pageSize);
        params.put("limit", pageSize);
        return this;
    }

    public Request put(String key, Object value) {
        params.put(key, value);
        return this;
    }

    public String getString(String key) {
        if (params == null || params.get(key) == null) {
            return null;
        }
        Object value = params.get(key);
        if (value instanceof String) {
            if (StringUtils.isBlank((String) value)) {
                return null;
            }
            return (String) params.get(key);
        }
        return String.valueOf(value);

    }

    public <T> T[] getArray(String key, Class<T> clazz) {
        if (params == null || params.get(key) == null) {
            return null;
        }

        Object value = params.get(key);
        if (value.getClass().isArray()) {
            try {

                Object[] arr = (Object[]) value;
                T[] ts = (T[]) Array.newInstance(clazz, arr.length);

                for (int i = 0; i < arr.length; i++) {
                    ts[i] = Convert.convert(clazz, arr[i]);
                }
                return ts;
            } catch (Exception e) {
                log.warn("Request get array failed");
            }
        }
        return null;
    }

    public Boolean getBoolean(String key) {
        String value = getString(key);
        if (value == null) {
            return null;
        }
        return Boolean.valueOf(value);
    }

    public Byte getByte(String key) {
        String value = getString(key);
        if (value == null) {
            return null;
        }
        return Byte.valueOf(value);
    }

    public Short getShort(String key) {
        String value = getString(key);
        if (value == null) {
            return null;
        }
        return Short.valueOf(value);
    }

    public Integer getInteger(String key) {
        String value = getString(key);
        if (value == null) {
            return null;
        }
        return Integer.valueOf(value);
    }

    public Long getLong(String key) {
        String value = getString(key);
        if (value == null) {
            return null;
        }
        return Long.valueOf(value);
    }

    public Float getFloat(String key) {
        String value = getString(key);
        if (value == null) {
            return null;
        }
        return Float.valueOf(value);
    }

    public Double getDouble(String key) {
        String value = getString(key);
        if (value == null) {
            return null;
        }
        return Double.valueOf(value);
    }

    public BigDecimal getDecimal(String key) {
        String value = getString(key);
        if (value == null) {
            return null;
        }
        return new BigDecimal(value);
    }

    public Date getDate(String key, String pattern) {
        String value = getString(key);
        if (StringUtils.isBlank(value)) {
            return null;
        }
        try {
            return new SimpleDateFormat(pattern).parse(value);
        } catch (ParseException e) {
            throw new DateParseException("Request get date and convert date faied", e);
        }
    }

    public boolean isNotBlank(String key) {
        return StringUtils.isNotBlank(this.getString(key));
    }

    public boolean isBlank(String key) {
        return !isNotBlank(key);
    }

    public <T> T convertObj(Class<T> clazz) {
        return JacksonUtils.parse(JacksonUtils.toJsonString(clazz), clazz);
    }

    public Request like(String key) {
        if (StringUtils.isNotBlank((String) this.params.get(key))) {
            this.params.put(key, "%" + this.params.get(key) + "%");
        }
        return this;
    }
}
